﻿using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using RaGE_JD.Properties;

namespace RaGE_JD
{
    internal class GetXYZ
    {
        private IntPtr _hProcess;
        private readonly int? _lpNumberOfBytesRead;
        public float DirX;
        public float DirY;
        public float DirZ;
        public float PosX;
        public float PosY;
        public float PosZ;
        public bool isValid;
        public ArrayList clientOffsets;
        public string ProcessesName;

        [DllImport("Kernel32.dll")]
        [MethodImpl(MethodImplOptions.ForwardRef)]
        private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, int lpNumberOfBytesRead);

        private int ReadInt(int address, int length)
        {
            if (length > 4)
            {
                length = 4;
            }
            if (length < 1)
            {
                length = 4;
            }
            var array = new byte[4];
            var lpBaseAddress = (IntPtr)address;

            if (_lpNumberOfBytesRead != null && !ReadProcessMemory(_hProcess, lpBaseAddress, array, length, (int)_lpNumberOfBytesRead))
                throw new Exception("Read memory error.");

            return BitConverter.ToInt32(array, 0);
        }

        private string ReadString(int address, int length)
        {
            var array = new byte[length];
            var lpBaseAddress = (IntPtr)address;

            if (_lpNumberOfBytesRead != null && !ReadProcessMemory(_hProcess, lpBaseAddress, array, length, (int)_lpNumberOfBytesRead))
                throw new Exception("Read memory error.");

            var encoding = Encoding.GetEncoding("gb2312");
            return encoding.GetString(array);
        }

        private float ReadFloat(int address)
        {
            var array = new byte[4];
            var lpBaseAddress = (IntPtr)address;

            if (_lpNumberOfBytesRead != null && !ReadProcessMemory(_hProcess, lpBaseAddress, array, 4, (int)_lpNumberOfBytesRead))
                throw new Exception("Read memory error");

            return BitConverter.ToSingle(array, 0);
        }

        public void Get(int ver)
        {
            if (ver < 0 || ver >= clientOffsets.Count) return;

            var processesByName = Process.GetProcessesByName(ProcessesName);

            if (processesByName.Length > 0)
            {
                var process = processesByName[0];
                var handle = process.Handle;
                _hProcess = handle;
                var offset = (Offset)clientOffsets[ver];

                var num = offset.BaseChain.Aggregate(0, (current, t) => ReadInt(current + t, 0));

                PosX = ReadFloat(num + offset.PosX);
                PosY = ReadFloat(num + offset.PosY);
                PosZ = ReadFloat(num + offset.PosZ);
                DirX = ReadFloat(num + offset.DirX);
                DirY = ReadFloat(num + offset.DirY);
                DirZ = ReadFloat(num + offset.DirZ);
                isValid = true;
            }
            else
            {
                MessageBox.Show(Resources.GameNoRunMultClients);
            }
        }

        public GetXYZ()
        {
            _lpNumberOfBytesRead = null;
            ProcessesName = "elementclient";
            clientOffsets = new ArrayList();

            if (!File.Exists(Application.StartupPath + "\\jdoffsets.txt")) return;

            try
            {
                var encoding = Encoding.GetEncoding("GB2312");
                var streamReader = new StreamReader(Application.StartupPath + "\\jdoffsets.txt", encoding);
                var separator = new[] { ' ' };

                while (true)
                {
                    var text = streamReader.ReadLine();

                    if (text == null)
                        break;

                    if (text.StartsWith("ProcessesName="))
                        ProcessesName = text.Substring(14);

                    if (!text.StartsWith("Name=")) continue;

                    var offset = new Offset();
                    offset.Version = text.Substring(5);
                    var readLine = streamReader.ReadLine();

                    if (readLine != null)
                    {
                        var array = readLine.Split(separator);
                        offset.BaseChain = new int[array.Length];

                        for (var i = 0; i < array.Length; i++)
                            offset.BaseChain[i] = int.Parse(array[i], NumberStyles.HexNumber);
                    }
                    offset.DirX = int.Parse(streamReader.ReadLine(), NumberStyles.HexNumber);
                    offset.DirY = int.Parse(streamReader.ReadLine(), NumberStyles.HexNumber);
                    offset.DirZ = int.Parse(streamReader.ReadLine(), NumberStyles.HexNumber);
                    offset.PosX = int.Parse(streamReader.ReadLine(), NumberStyles.HexNumber);
                    offset.PosY = int.Parse(streamReader.ReadLine(), NumberStyles.HexNumber);
                    offset.PosZ = int.Parse(streamReader.ReadLine(), NumberStyles.HexNumber);
                    clientOffsets.Add(offset);
                }
                streamReader.Close();
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch (Exception)
            // ReSharper restore EmptyGeneralCatchClause
            {
            }
        }
    }
}
